﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Security;
using System.Security.Cryptography;


namespace P2PChat.Security.Cryptography
{
    /// <summary>
    /// 提供RSA加密
    /// </summary>
    public class RSACryptography : IEncryptography
    {
        #region 成员
        public string key = null;
        /// <summary>
        /// 获取或创建密钥
        /// </summary>
        public string Key
        {
            get { return key; }
            set
            {
                key = value;
            }
        }
        private RSAKeyType keyType = RSAKeyType.NoKey;
        public RSAKeyType KeyType { get { return keyType; } }
        #endregion
        

        #region 其他行为
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string SetKey()
        {
            string[] keys = RSACryptography.GenerateKeyStrings();
            this.key = keys[1];
            keyType = RSAKeyType.PrivateKey;
            return keys[0];
        }

        public void GetKey(string key)
        {
            this.key = key;
            keyType = RSAKeyType.PublicKey;
        }

        public void ClearKey()
        {
            key = null;
            keyType = RSAKeyType.NoKey;
        }
        #endregion

        #region 接口IEncryptography的实现
        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="plainStr">字符串原文</param>
        /// <returns></returns>
        public string Encrypt(string plainStr)
        {
            if (this.Key == null)
            {
                throw new NullReferenceException("没有定义密钥！");
            }
            else
            {
                byte[] plainData = Encoding.UTF8.GetBytes(plainStr);
                byte[] cipherBytes = Encrypt(plainData);

                StringBuilder sbString = new StringBuilder();
                for (int i = 0; i < cipherBytes.Length; i++)
                {
                    sbString.Append(cipherBytes[i] + ",");
                }
                return sbString.ToString();
            }
        }

        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="encryptedStr">字符串密文</param>
        /// <returns></returns>
        public string Decrypt(string encryptedStr)
        {
            if (this.key == null)
            {
                throw new NullReferenceException("没有定义密钥！");
            }
            else
            {
                byte[] plainData = Encoding.UTF8.GetBytes(encryptedStr);
                byte[] decBytes = Decrypt(plainData);

                StringBuilder sbString = new StringBuilder();
                for (int i = 0; i < decBytes.Length; i++)
                {
                    sbString.Append(decBytes[i] + ",");
                }
                return sbString.ToString();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="encryptedStr"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryDecrypt(string encryptedStr, out string result)
        {
            if (this.key == null)
            {
                result = null;
                return false;
            }
            else
            {
                byte[] plainData = Encoding.UTF8.GetBytes(encryptedStr);
                byte[] decBytes = Decrypt(plainData);

                StringBuilder sbString = new StringBuilder();
                for (int i = 0; i < decBytes.Length; i++)
                {
                    sbString.Append(decBytes[i] + ",");
                }
                result = sbString.ToString();
                return true;
            }
        }

        /// <summary>
        /// 加密一段数据
        /// </summary>
        /// <param name="plainData">数据</param>
        /// <returns></returns>
        public byte[] Encrypt(byte[] plainData)
        {
            if (this.Key == null)
            {
                throw new NullReferenceException("没有定义密钥！");
            }
            else
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(Key);
                byte[] cipherBytes;
                byte[] byteEn = rsa.Encrypt(Encoding.UTF8.GetBytes("a"), false);
                cipherBytes = rsa.Encrypt(plainData, false);

                return cipherBytes;
            }
        }

        public byte[] Decrypt(byte[] encryptedData)
        {
            if (Key == null)
            {
                throw new NullReferenceException("在定义密钥之前尝试解密");
            }
            else
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(Key);
                byte[] byteEn = rsa.Encrypt(Encoding.UTF8.GetBytes("a"), false);
                byte[] decBytes = rsa.Decrypt(encryptedData, false);
                return decBytes;
            }
        }

        public bool TryDecrypt(byte[] encryptedData, out byte[] result)
        {
            if (key == null)
            {
                result = null;
                return false;
            }
            else
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(Key);
                byte[] byteEn = rsa.Encrypt(Encoding.UTF8.GetBytes("a"), false);
                byte[] decBytes = rsa.Decrypt(encryptedData, false);
                result = decBytes;
                return true;
            }
            
        }
        #endregion

        #region 静态成员
        /// <summary>
        /// 获取一对RSA密钥
        /// </summary>
        /// <returns>string[] sKeys :
        ///   sKeys[0]: 公钥
        ///   sKeys[1]: 私钥
        /// </returns>
        public static string[] GenerateKeyStrings()
        {
            string[] sKeys = new string[2];
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            sKeys[0] = rsa.ToXmlString(true);
            sKeys[1] = rsa.ToXmlString(false);
            return sKeys;
        }
        #endregion



    }

    /// <summary>
    /// 代表RSA的密钥类型
    /// </summary>
    public enum RSAKeyType
    {
        /// <summary>
        /// 未存储任何密钥类型
        /// 当密钥类型为NoKey时,Key的值应该为空值
        /// </summary>
        NoKey,
        /// <summary>
        /// 公钥
        /// </summary>
        PublicKey,
        /// <summary>
        /// 私钥
        /// </summary>
        PrivateKey
    }
}
